package nature.nano.util.pipe;

import java.util.Stack;

import nature.nano.component.EmptyProps;
import nature.nano.component.PrimaryPipe;
import nature.nano.component.SimpleProps;
import nature.nano.component.Strings;
import nature.nano.iface.Accepter;
import nature.nano.iface.Props;
import nature.nano.iface.enumer.EnumStringPairCallback;

public class ErrorNormalizer extends PrimaryPipe {

	private class Data {
		String type;
		Props props;
		Data(String type, Props props) {
			this.type = type;
			this.props = props;
		}
	}
	private Stack<Data> stack = new Stack<Data>();

	public ErrorNormalizer() {
		props(Strings.detail);
	}
	
	@Override
	public void anBegin(String type, Props props) {
		Accepter accepter = slot(Strings.output);
		if (stack.size() == 0) {
			accepter.onBegin(Strings.root, EmptyProps.instance);
		}
		if (type.equals(Strings.error)) {
			String detail = prop(Strings.detail);
			if (!(detail != null && detail.equals(Strings.boolTrue))) {
				String path = getErrorDetailPath();
				if (path != null) {
					SimpleProps newProps = new SimpleProps(props);
					newProps.add(Strings.location, path);
					props = newProps;
				}
			}
			accepter.onBegin(Strings.error, props);
			accepter.onEnd(Strings.error);
		}
		stack.push(new Data(type, props));
	}

	@Override
	public void anEnd(String type) {
		stack.pop();
		if (stack.size() == 0) {
			slot(Strings.output).onEnd(Strings.root);
		}
	}
	
	private String getErrorDetailPath() {
		final StringBuilder builder = new StringBuilder();
		int size = stack.size();
		if (size <= 1) {
			return null;
		}
		for (int i = 0; i < size; ++i) {
			Data data = stack.get(i);
			builder.append(data.type);
			if (data.props != null && data.props.propCount() != 0) {
				builder.append(Strings.lb);
				data.props.enumProp(
					new EnumStringPairCallback() {
						public void onRead(String key, String value) {
							builder.append(key);
							builder.append(Strings.equal);
							builder.append(value);
							builder.append(Strings.comma);
						}			
					});
				builder.deleteCharAt(builder.length() - 1);
				builder.append(Strings.rb);
			}
			if (i != size - 1) {
				builder.append(Strings.period);
			}
		}
		return builder.toString();
	}

}
